package 遍历器;

import 作用域相关.*;
import 抽象语法树节点.*;
import 抽象语法树节点.字面量类.字符型字面量;
import 抽象语法树节点.字面量类.整数型字面量;
import 抽象语法树节点.字面量类.浮点型字面量;
import 抽象语法树节点.字面量类.逻辑型字面量;
import 抽象语法树节点.语句类.返回语句;

public class 定义监听器 extends 抽象语法树基础监听器 {

    public 符号表 符号表;

    private 作用域 当前作用域;


    @Override
    public void 进入编译单元(编译单元 节点) {
        符号表 = new 符号表();
        当前作用域 = 符号表.全局作用域;
        节点.作用域 = 当前作用域;
        System.out.println("进入全局作用域");
    }

    @Override
    public void 离开编译单元(编译单元 节点) {
        System.out.println("离开全局作用域");
        当前作用域 = null;
    }

    @Override
    public void 进入结构体定义(结构体定义 节点) {
        System.out.println("行 " + 节点.token.getLine() + " 定义结构体 " + 节点.名称);
        var 结构体 = new 结构体符号(节点.名称, 当前作用域);
        节点.作用域 = 当前作用域;
        节点.符号 = 结构体;
        结构体.节点 = 节点;
        当前作用域.定义(结构体);
        当前作用域 = 结构体;
    }

    @Override
    public void 离开结构体定义(结构体定义 节点) {
        System.out.println("离开结构体 " + 节点.名称);
        当前作用域 = 当前作用域.取外围作用域();
    }

    @Override
    public void 进入变量定义(变量定义 节点) {
        System.out.println("行 " + 节点.token.getLine() + " 定义变量 " + 节点.名称);
        var 变量 = new 变量符号(节点.名称, null);
        节点.作用域 = 当前作用域;
        节点.符号 = 变量;
        变量.节点 = 节点;
        当前作用域.定义(变量);
    }


    @Override
    public void 进入数组定义(数组定义 节点) {
        System.out.println("行 " + 节点.token.getLine() + " 定义数组变量 " + 节点.名称);
        var 变量 = new 变量符号(节点.名称, null);
        节点.作用域 = 当前作用域;
        节点.符号 = 变量;
        变量.节点 = 节点;
        当前作用域.定义(变量);
    }

    @Override
    public void 进入方法定义(方法定义 节点) {
        System.out.println("行 " + 节点.token.getLine() + " 定义方法 " + 节点.名称);

        var 方法 = new 方法符号(节点.名称, null, 当前作用域);
        节点.作用域 = 当前作用域;
        节点.符号 = 方法;
        方法.节点 = 节点;

        当前作用域.定义(方法);
        当前作用域 = 方法;
    }

    @Override
    public void 离开方法定义(方法定义 节点) {
        System.out.println("离开方法 " + 节点.名称);
        当前作用域 = 当前作用域.取外围作用域();
    }

    @Override
    public void 进入返回语句(返回语句 节点) {
        节点.作用域 = 当前作用域;
    }

    @Override
    public void 进入代码块(代码块 节点) {
        System.out.println("进入代码块");
        var 局部作用域 = new 局部作用域(当前作用域);
        节点.作用域 = 局部作用域;
        当前作用域 = 局部作用域;
    }

    @Override
    public void 离开代码块(代码块 节点) {
        System.out.println("离开代码块");
        当前作用域 = 当前作用域.取外围作用域();
    }

    @Override
    public void 进入类型引用(类型引用 节点) {
        节点.作用域 = 当前作用域;
    }

    @Override
    public void 进入标识符(标识符 节点) {
        节点.作用域 = 当前作用域;
    }

    @Override
    public void 进入整数型字面量(整数型字面量 节点) {
        节点.作用域 = 当前作用域;
    }

    @Override
    public void 进入浮点型字面量(浮点型字面量 节点) {
        节点.作用域 = 当前作用域;
    }

    @Override
    public void 进入字符型字面量(字符型字面量 节点) {
        节点.作用域 = 当前作用域;
    }

    @Override
    public void 进入逻辑型字面量(逻辑型字面量 节点) {
        节点.作用域 = 当前作用域;
    }
}
